package com.example.javamediaserver.service;

import com.example.javamediaserver.config.MediaServerConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
@Slf4j
public class HlsService {

    private final MediaServerConfig config;
    
    // 活动的HLS转码任务
    private final Map<String, HlsTranscoder> transcoders = new ConcurrentHashMap<>();
    
    // HLS任务监控线程池
    private ScheduledExecutorService scheduler;
    
    @PostConstruct
    public void init() {
        try {
            // 确保HLS目录存在
            Path hlsPath = config.getHls().getAbsolutePath();
            Files.createDirectories(hlsPath);
            log.info("HLS目录已创建: {}", hlsPath);
            
            // 启动监控线程
            scheduler = Executors.newScheduledThreadPool(1);
            scheduler.scheduleAtFixedRate(this::monitorTranscoders, 30, 30, TimeUnit.SECONDS);
        } catch (IOException e) {
            log.error("创建HLS目录失败", e);
        }
    }
    
    // 开始HLS转码
    public boolean startHlsTranscoding(String streamPath, String rtmpUrl) {
        if (transcoders.containsKey(streamPath)) {
            log.warn("HLS转码已存在: {}", streamPath);
            return false;
        }
        
        try {
            // 解析流路径
            String[] parts = streamPath.split("/");
            if (parts.length < 3) {
                log.error("无效的流路径: {}", streamPath);
                return false;
            }
            
            String app = parts[1];
            String streamKey = parts[2];
            
            // 创建HLS输出目录
            Path hlsDir = config.getHls().getAbsolutePath().resolve(app).resolve(streamKey);
            Files.createDirectories(hlsDir);
            
            // 创建转码器
            HlsTranscoder transcoder = new HlsTranscoder(
                    rtmpUrl,
                    hlsDir.resolve("index.m3u8").toString(),
                    config.getHls().getSegmentDuration(),
                    config.getHls().getPlaylistSize());
            
            // 启动转码线程
            Thread transcoderThread = new Thread(transcoder::start);
            transcoderThread.setDaemon(true);
            transcoderThread.start();
            
            // 添加到转码任务列表
            transcoders.put(streamPath, transcoder);
            
            log.info("开始HLS转码: {} -> {}", streamPath, hlsDir);
            return true;
        } catch (Exception e) {
            log.error("开始HLS转码失败: {}", streamPath, e);
            return false;
        }
    }
    
    // 停止HLS转码
    public void stopHlsTranscoding(String streamPath) {
        HlsTranscoder transcoder = transcoders.remove(streamPath);
        if (transcoder != null) {
            transcoder.stop();
            log.info("停止HLS转码: {}", streamPath);
        }
    }
    
    // 监控转码任务
    private void monitorTranscoders() {
        transcoders.forEach((streamPath, transcoder) -> {
            if (!transcoder.isRunning()) {
                log.warn("HLS转码任务已停止: {}, 正在移除", streamPath);
                transcoders.remove(streamPath);
            }
        });
        
        log.debug("当前HLS转码任务数: {}", transcoders.size());
    }
    
    // HLS转码器实现
    static class HlsTranscoder {
        private final String inputUrl;
        private final String outputUrl;
        private final int segmentDuration;
        private final int playlistSize;
        
        private volatile boolean running = false;
        private volatile boolean stopRequested = false;
        
        public HlsTranscoder(String inputUrl, String outputUrl, int segmentDuration, int playlistSize) {
            this.inputUrl = inputUrl;
            this.outputUrl = outputUrl;
            this.segmentDuration = segmentDuration;
            this.playlistSize = playlistSize;
        }
        
        public void start() {
            if (running) {
                return;
            }
            
            running = true;
            stopRequested = false;
            
            FFmpegFrameGrabber grabber = null;
            FFmpegFrameRecorder recorder = null;
            
            try {
                // 创建抓取器
                grabber = new FFmpegFrameGrabber(inputUrl);
                grabber.setOption("rtmp_live", "live");
                grabber.start();
                
                // 创建录制器
                recorder = new FFmpegFrameRecorder(outputUrl, 
                        grabber.getImageWidth(), 
                        grabber.getImageHeight(),
                        grabber.getAudioChannels());
                
                // 设置HLS参数
                recorder.setFormat("hls");
                recorder.setOption("hls_time", String.valueOf(segmentDuration));
                recorder.setOption("hls_list_size", String.valueOf(playlistSize));
                recorder.setOption("hls_flags", "delete_segments");
                
                // 复制编解码器参数
                recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
                recorder.setFrameRate(grabber.getFrameRate());
                recorder.setVideoBitrate(grabber.getVideoBitrate());
                recorder.setAudioBitrate(grabber.getAudioBitrate());
                recorder.setSampleRate(grabber.getSampleRate());
                
                recorder.start();
                
                // 转码循环
                while (!stopRequested) {
                    try {
                        // 抓取并写入帧
                        recorder.record(grabber.grabFrame());
                    } catch (Exception e) {
                        if (!stopRequested) {
                            log.error("HLS转码帧处理错误", e);
                            break;
                        }
                    }
                }
            } catch (Exception e) {
                log.error("HLS转码失败", e);
            } finally {
                // 关闭资源
                try {
                    if (recorder != null) {
                        recorder.close();
                    }
                    
                    if (grabber != null) {
                        grabber.close();
                    }
                } catch (Exception e) {
                    log.error("关闭HLS转码资源失败", e);
                }
                
                running = false;
            }
        }
        
        public void stop() {
            stopRequested = true;
        }
        
        public boolean isRunning() {
            return running;
        }
    }
} 